/*
 *  mainwindow.cpp
 *  Perceel
 *
 *  Created by Nicola Gigante on 15/03/08.
 *  Copyright 2008 Nicola Gigante. All rights reserved.
 *
 */

#include "mainwindow.h"

MainWindow::MainWindow()
{
	setupUi(this);
	
	setUnifiedTitleAndToolBarOnMac(true);
	
	splitter->setSizes(QList<int>() << 70 << 30);
	
	QActionGroup *group = new QActionGroup(this);
	group->addAction(pointModeAction);
	group->addAction(dragModeAction);
	group->setExclusive(true);
	
	connect(group, SIGNAL(triggered(QAction *)), this, SLOT(modeChanged(QAction *)));
	
	qApp->installEventFilter(this);
	
	windowMenu->addAction(tfDock->toggleViewAction());
	
	manager = new TFListManager(this);
	delegate = new TFListDelegate(this);
	
	functionsList->setModel(manager);
	functionsList->setItemDelegate(delegate);
	
	connect(manager, SIGNAL(modified(bool)), this, SLOT(updateWindowTitle()));
	
	connect(addTFAction, SIGNAL(triggered()), this, SLOT(newFunction()));
	connect(removeTFAction, SIGNAL(triggered()), this, SLOT(closeFunction()));
	
	connect(functionsList->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(changeTF(const QModelIndex &)));
	
	connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
	connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
	connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
	connect(exportImageAction, SIGNAL(triggered()), this, SLOT(exportImage()));
	connect(zoomInAction, SIGNAL(triggered()), plotWidget, SLOT(zoomIn()));
	connect(zoomOutAction, SIGNAL(triggered()), plotWidget, SLOT(zoomOut()));
	connect(clearRecentsAction, SIGNAL(triggered()), this, SLOT(clearRecents()));
	connect(printPreviewAction, SIGNAL(triggered()), this, SLOT(printPreview()));
	connect(printAction, SIGNAL(triggered()), this, SLOT(print()));
	
	connect(plotWidget, SIGNAL(detailsChanged(const QMap<QString, QString> &)), detailsView, SLOT(setDetails(const QMap<QString, QString> &)));
	
	connect(preferencesAction, SIGNAL(triggered()), this, SLOT(showPref()));
	
	connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
	connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
	connect(helpAction, SIGNAL(triggered()), this, SLOT(showHelp()));
	connect(licenseAction, SIGNAL(triggered()), this, SLOT(showLicense()));
	
	readSettings();
}

void MainWindow::about()
{
	QString text("<div style=\"font-weight: normal;\">"
				 "<p><big>%1 %2</big></p>"
				 "<p>%3</p>"
				 "<p>%4</p>"
				 "<p>%5"
				 "   <ul>"
				 "      <li><b>%6</b>: %7</li>"
				 "		<li><b>%8</b>: %9</li>"
				 "		<li><b>%10</b>: %11</li>"
				 "	 </ul></p></div>");
	text =  text.arg(tr("Perceel version"), PERCEEL_VERSION).
				 arg(tr("Perceel is a simple, lightweight, student-friendly application "
					 "for analysis of linear, continuous systems.")).
				 arg(tr("Perceel is free software. You can copy and/or modify it under the "
					 "terms of the GNU General Public License, as published by "
					 "Free Software Foundation, either version 2 or 3 or any later version.")).
				 arg(tr("Credits:")).
				 arg("Nicola Gigante", tr("Concept, Project, Code, IT and EN translations, everything else..")).
				 arg("Dree", tr("Windows installer and friulian translation")).
				 arg("Filipe Azevedo", tr("French translation"));
	
	QMessageBox (QMessageBox::Information, tr("About Perceel"), text, QMessageBox::Close, this, Qt::Sheet).exec();
					   
}

void MainWindow::showHelp()
{
#ifdef Q_WS_MAC
	QString s = "file://" + QDir::currentPath() + "/Perceel.app/Contents/Resources/help.pdf";
	QDesktopServices::openUrl(s);
#elif defined Q_OS_WIN32
	QString s = "start \"%1\\help.pdf\"";
	QProcess::execute(s.arg(QDir::currentPath()));
#endif
	
}

void MainWindow::showLicense()
{
#ifdef Q_WS_MAC
	QString s = "file://" + QDir::currentPath() + "/Perceel.app/Contents/Resources/license.pdf";
	QDesktopServices::openUrl(s);
#elif defined Q_OS_WIN32
	QString s = "start " + QDir::currentPath() + "\\license.pdf";
	QProcess::execute(s);
#endif
		
}

void MainWindow::readSettings()
{
	QSettings s;
	
	// Recent open files list
	settings.recentList = s.value("settings/recentList").toStringList();
	settings.recentsCount = s.value("settings/recentsListCount").toInt();
	
	if(settings.recentList.count() == 0)
	{
		openRecentMenu->setEnabled(false);
		return;
	}
	
	int i = 0;
	foreach(QString filename, settings.recentList)
	{
		if(++i >= settings.recentsCount)
			break;
		QAction *a = new QAction(this);
		a->setText(QFileInfo(filename).fileName());
		a->setData(filename);
		a->setVisible(true);
		connect(a, SIGNAL(triggered()), this, SLOT(openRecentFile()));
		openRecentMenu->addAction(a);	
	}
	
	openRecentMenu->addSeparator();
	openRecentMenu->addAction(clearRecentsAction);
	
	// Other
	settings.openAfterExporting = s.value("settings/openAfterExporting", true).toBool();
}

void MainWindow::storeSettings()
{
	QSettings s;
	
	s.setValue("settings/recentList", settings.recentList);
	s.setValue("settings/openAfterExporting", settings.openAfterExporting);
}

void MainWindow::clearRecents()
{
	settings.recentList.clear();
}

void MainWindow::modeChanged(QAction *action)
{
	if(action == pointModeAction)
		plotWidget->setPointerMode(PlotWidget::PointMode);
	else if(action == dragModeAction)
		plotWidget->setPointerMode(PlotWidget::DragMode);
	
	detailsView->clear();
}

void MainWindow::openRecentFile()
{
	QAction *action = qobject_cast<QAction *>(sender());
	if (action)
		open(action->data().toString());
}

bool MainWindow::event(QEvent *event)
{
	if (!isActiveWindow() || !manager || manager->isNew())
		return QMainWindow::event(event);
	
	switch (event->type())
	{
		case QEvent::IconDrag:
            event->accept();
			switch(qApp->keyboardModifiers())
			{
				case Qt::NoModifier: {
					QDrag *drag = new QDrag(this);
					QMimeData *data = new QMimeData();
					
					data->setUrls(QList<QUrl>() << QUrl::fromLocalFile(manager->filename()));
					drag->setMimeData(data);
					
					QPixmap cursorPixmap = style()->standardPixmap(QStyle::SP_FileIcon, 0, this); 
					drag->setPixmap(cursorPixmap);
				
					QPoint hotspot(cursorPixmap.width() - 5, 5);
					drag->setHotSpot(hotspot);
				
					drag->start(Qt::LinkAction | Qt::CopyAction);
				}
					break;
				case Qt::AltModifier: {
					QMenu menu(this);
					connect(&menu, SIGNAL(triggered(QAction *)), this, SLOT(openProxyMenu(QAction *)));
				
					QFileInfo info(manager->filename());
					QAction *action = menu.addAction(info.fileName());
					
					action->setIcon(style()->standardPixmap(QStyle::SP_FileIcon, 0, this));
					
					QStringList folders = info.absolutePath().split('/');
				
					for(int i = folders.count() - 1; i >= 0; i--)
					{
						QString string = folders.at(i);
						QIcon icon;
					
						if (string != "") {
							icon = style()->standardIcon(QStyle::SP_DirClosedIcon, 0, this);
						} else { // At the root
							string = "/";
							icon = style()->standardIcon(QStyle::SP_DriveHDIcon, 0, this);
						}
						
						action = menu.addAction(string);
						action->setIcon(icon);
					}
					
					QPoint pos(QCursor::pos().x() - 20, frameGeometry().y());
					menu.exec(pos);
				}
					break;
				default:
					event->ignore();
			}
            return true;
		default:
            return QMainWindow::event(event);
	}
}

void MainWindow::openProxyMenu(QAction *action)
{
	QString path = manager->filename().left(manager->filename().indexOf(action->text())) + action->text();
	
	if (path == manager->filename())
		return;
	QProcess process;
	process.start("/usr/bin/open", QStringList() << path, QIODevice::ReadOnly);
	process.waitForFinished();
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
	if (event->type() == QEvent::FileOpen) {
		QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
		open(openEvent->file());
		return true;
	} else
		return QObject::eventFilter(obj, event);
}

void MainWindow::newFunction()
{	
	TFDialog d(this);
	
	d.adjustSize();
	
	if(d.exec())
		manager->addFunction(d.tf());
}

void MainWindow::closeFunction()
{
	manager->delFunction(functionsList->selectionModel()->currentIndex().row());
}

void MainWindow::changeTF(const QModelIndex &selection)
{
	plotWidget->setTF(selection.data().value<TF>());
}

void MainWindow::updateWindowTitle()
{
	QString t = "Perceel";
	
	if(!manager->isNew())
		t += " - " + manager->filename();
	
	t += "[*]";
	
	setWindowTitle(t);
	setWindowModified(manager->modified());
}

void MainWindow::closeEvent(QCloseEvent *event)
{
	switch(close())
	{
		case QMessageBox::Cancel:
			event->ignore();
			break;
		default:
			event->accept();
			storeSettings();
			break;
	}
}

QMessageBox::StandardButton MainWindow::close()
{
	if(manager->modified())
	{
		QMessageBox::StandardButton b = QMessageBox::question(this,
															  tr("Perceel"),
															  tr("Do you want to save the changes made to your functions set?"),
															  QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
															  QMessageBox::Cancel);
		switch(b)
		{
			case QMessageBox::Save:
				if(save())
				{
					delete manager;
					manager = new TFListManager(this);
					functionsList->setModel(manager);
					updateWindowTitle();
					return b;
				}
				else
					return QMessageBox::Cancel;
			case QMessageBox::Discard:
				delete manager;
				manager = new TFListManager(this);
				functionsList->setModel(manager);
				updateWindowTitle();
				return b;
			default:
				return b;
		}
	}
	
	return QMessageBox::Save;
}

bool MainWindow::open(QString filename)
{
	if(filename.isNull() || filename.isEmpty())
	{
		filename = QFileDialog::getOpenFileName(this, tr("Open a function set"), QString(), tr("Perceel transfer function sets (*.tf)"));
		if(filename.isNull())
			return false;
	}
	
	addToRecentList(filename);
	
	if(close() == QMessageBox::Cancel)
		return false;
	
	if(!manager->open(filename))
	{
		QMessageBox::critical(this, "Perceel", tr("Unable to open the functions set %1").arg(filename));
		return false;
	}
	
	return true;
}

bool MainWindow::save()
{
	if(!manager->modified())
		return true;
	
	if(manager->isNew())
	{
		QString filename = QFileDialog::getSaveFileName(this, tr("Save a function set"), QString(), tr("Perceel transfer function sets (*.tf)"));
		if(filename.isNull())
			return false;
		manager->setFilename(filename);
	}
	
	addToRecentList(manager->filename());
	
	if(!manager->save())
	{
		QMessageBox::critical(this, "Perceel", tr("Unable to save the functions set."));
		return false;
	}
	
	return true;
}

void MainWindow::addToRecentList(QString filename)
{
	settings.recentList.removeOne(filename);
	
	settings.recentList.push_front(filename);
	if(settings.recentList.count() > settings.recentsCount)
		settings.recentList.pop_back();
}

bool MainWindow::exportImage()
{	
	QStringList l = QStringList() << tr("Windows bitmap files (*.bmp)")
								  << tr("JPEG image files (*.jpg *.jpeg)")
								  << tr("PNG image files (*.png)")
								  << tr("TIFF image files (*.tiff)")
								  << tr("XPM image files (*.xpm)");
	
	QStringList fmts = QStringList() << "BMP" << "JPG" << "PNG" << "TIFF" << "XPM";
	
	QString format;
	QString path = QFileDialog::getSaveFileName(this, tr("Export as image"), QString(), l.join(";;"), &format);
	
	if(path.isNull())
		return false;
	
	format = fmts.at(l.indexOf(format));
	
	QImage image;
	
	image = plotWidget->doRendering(true);
	
	QImageWriter (path, format.toAscii()).write(image);
	
	if(settings.openAfterExporting)
		QDesktopServices::openUrl("file://" + path);
	
	return true;
}

void MainWindow::printPreview()
{
	QPrinter printer;
	QPrintPreviewDialog dialog(&printer, this, Qt::Sheet);
	connect(&dialog, SIGNAL(paintRequested(QPrinter *)), this, SLOT(print(QPrinter *)));
	dialog.exec();
}

bool MainWindow::print(QPrinter *printer)
{
	bool userInput = false;
	if(!printer)
	{
		printer = new QPrinter();
		userInput = true;
	}
	
	if(userInput)
	{
		QPrintDialog dialog(printer, this);
		if(dialog.exec() != QDialog::Accepted)
			return false;
	}
	
	// Draw the function
	TFRenderer tfRenderer;
	tfRenderer.setTF(plotWidget->tf());
	QPicture tfPicture = tfRenderer.paintTF();
	QSize tfSize = tfRenderer.sizeHint();
	
	// Draw the image
	QImage image = plotWidget->doRendering(true);
	image = image.scaled(printer->pageRect().size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
	
	// Actually to the printing
	QPainter painter(printer);
	
	QPoint p = printer->pageRect().topLeft();
	painter.drawText(p, manager->filename());
	p.ry() += painter.fontMetrics().boundingRect(manager->filename()).height() + 10;
	
	QString tfMsg = tr("Transfer function:");
	painter.drawText(p, tfMsg);
	p.ry() += painter.fontMetrics().boundingRect(tfMsg).height();
	
	painter.drawPicture(p, tfPicture);
	p.ry() += tfSize.height() + 10;
	
	painter.drawImage(p, image);
	
	painter.end();
	
	if(userInput)
		delete printer;
	
	return true;
}

void MainWindow::showPref()
{
	PrefDialog *d = new PrefDialog(this);
	d->exec();
}





